/*!
 * \file nghttp2_parse.c
 *
 * \brief http/2.0 解析 函数
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 3.0
 * \author geyh
 * \date 2016/01/28
 *
 */

#include <frsoap_parse.h>
#include <iconv2utf8.h>
#include <frgzip_decompress.h>
#include "frct_comm.h"
#include "../comm/http_comm.h"

#include "nghttp2_header.h"
#include "../http_core.h"

extern void *g_p_apm_context;

/* Header Type Code */
#define HTTP2_DATA          0
#define HTTP2_HEADERS       1
#define HTTP2_PRIORITY      2
#define HTTP2_RST_STREAM    3
#define HTTP2_SETTINGS      4
#define HTTP2_PUSH_PROMISE  5
#define HTTP2_PING          6
#define HTTP2_GOAWAY        7
#define HTTP2_WINDOW_UPDATE 8
#define HTTP2_CONTINUATION  9
#define HTTP2_ALTSVC        0xA
#define HTTP2_BLOCKED       0xB

/*\ head frame 解析
 *
 * \p_packet                (Frbyte_Packet *        入力信息)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
int nghttp2_header_parse(Frbyte_Packet *p_packet, unsigned int ui_data_len, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    uint8_t u8_end_headers = 0, u8_end_stream = 0;
    uint8_t u8_padded = 0, u8_priority = 0;
    uint8_t u8_flags = 0;
    char *p_headers = NULL;
    int i_ret = 0;
    uint32_t u32_stream_id = 0;

    if(p_packet == NULL || p_st_private == NULL || ui_data_len == 0 || p_st_private->p_http2_sess == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_packet, &u8_flags);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u8_end_stream = (u8_flags & (uint8_t)(0x01));
    u8_end_headers = (u8_flags & (uint8_t)0x04);
    u8_padded = (u8_flags & (uint8_t)0x08);
    u8_priority = (u8_flags & (uint8_t)0x20 );


    //padded
    if(u8_padded)
    {
        i_ret = bytebuff_get_char(p_packet, &u8_padded);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;
    }

    //0... .... .... .... .... .... .... .... = Reserved: 0x00000000
    //.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
    i_ret = bytebuff_get_int(p_packet, 4, &u32_stream_id, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u32_stream_id = u32_stream_id & 0x7fffffff;
    p_st_private->p_http2_sess->u32_stream_id = u32_stream_id;

    if(p_st_private->i_frame_type != 1)
        p_st_private->u32_current_resp_id = u32_stream_id;

    if(u8_priority)
    {
        i_ret = bytebuff_get_char(p_packet, &u8_priority);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;
        //todo?
    }

    if(u8_padded)
    {
        if(p_packet->ui_remaining < u8_padded)
            return APM_L7_ANALYZE_FAIL;
    }

    if(ui_data_len > (unsigned int)bytebuff_remaining(p_packet))
        return APM_L7_ANALYZE_FAIL;
    
    p_headers = (char *)frmalloc(ui_data_len);
    if(p_headers == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_bytes(p_packet, p_headers, ui_data_len);
    if(i_ret == FR_FAIL)
    {
        frfree(p_headers);
        return APM_L7_ANALYZE_FAIL;
    }

    i_ret = http_header_inflate(p_headers, ui_data_len, p_st_private, p_st_body_data, i_flag_need);
    if(i_ret == FR_FAIL)
    {
        frfree(p_headers);
        return APM_L7_ANALYZE_FAIL;
    }

    frfree(p_headers);

    i_ret = bytebuff_skip(p_packet, u8_padded);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(u8_end_headers == 0 || u8_end_stream == 0)
    {
        bytebuff_truncate(p_packet);
        return APM_L7_ANALYZE_TODO;
    }


    return APM_L7_ANALYZE_SUCC;

}

/*\ head frame 解析
 *
 * \p_packet                (Frbyte_Packet *        入力信息)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
int nghttp2_push_promise_parse(Frbyte_Packet *p_packet, unsigned int ui_data_len, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    uint8_t u8_end_headers = 0, u8_end_stream = 0;
    uint8_t u8_padded = 0, u8_priority = 0;
    uint8_t u8_flags = 0;
    char *p_headers = NULL;
    int i_ret = 0;
    uint32_t u32_stream_id = 0;

    if(p_packet == NULL || p_st_private == NULL || p_st_private->p_http2_sess == NULL || ui_data_len == 0)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_packet, &u8_flags);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u8_end_stream = (u8_flags & (uint8_t)(0x01));
    u8_end_headers = (u8_flags & (uint8_t)0x04);
    u8_padded = (u8_flags & (uint8_t)0x08);
    u8_priority = (u8_flags & (uint8_t)0x20 );


    //padded
    if(u8_padded)
    {
        i_ret = bytebuff_get_char(p_packet, &u8_padded);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;
    }

    //0... .... .... .... .... .... .... .... = Reserved: 0x00000000
    //.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
    i_ret = bytebuff_get_int(p_packet, 4, &u32_stream_id, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u32_stream_id = u32_stream_id & 0x7fffffff;
    p_st_private->p_http2_sess->u32_stream_id = u32_stream_id;

    if(p_st_private->i_frame_type != 1)
        p_st_private->u32_current_resp_id = u32_stream_id;

    //另一个stream ID
    //0... .... .... .... .... .... .... .... = Reserved: 0x00000000
    //.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
    i_ret = bytebuff_skip(p_packet, 4);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(u8_priority)
    {
        i_ret = bytebuff_get_char(p_packet, &u8_priority);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;
        //todo?
    }

    if(u8_padded)
    {
        if(p_packet->ui_remaining < u8_padded)
            return APM_L7_ANALYZE_FAIL;
    }

    p_headers = (char *)frmalloc(ui_data_len);
    if(p_headers == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_bytes(p_packet, p_headers, ui_data_len);
    if(i_ret == FR_FAIL)
    {
        frfree(p_headers);
        return APM_L7_ANALYZE_FAIL;
    }

    i_ret = http_header_inflate(p_headers, ui_data_len, p_st_private, p_st_body_data, i_flag_need);
    if(i_ret == FR_FAIL)
    {
        frfree(p_headers);
        return APM_L7_ANALYZE_FAIL;
    }

    frfree(p_headers);

    i_ret = bytebuff_skip(p_packet, u8_padded);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(u8_end_headers == 0 || u8_end_stream == 0)
    {
        bytebuff_truncate(p_packet);
        return APM_L7_ANALYZE_TODO;
    }


    return APM_L7_ANALYZE_SUCC;

}

/*\ req 数据体分析 解析
 *
 * \p_packet                (Frbyte_Packet *        入力信息)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
FR_STATIC int __nghttp2_body_data_req(Frbyte_Packet *p_packet, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    int i_ret = 0;
    char *p_header_buff = NULL, *p_tmp = NULL;
    int i_header_buff_len = 0, i_tmp_len = 0;
    char arr_head[1024];
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_packet == NULL || p_st_private == NULL || p_st_private->p_http2_sess == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    if(p_comm_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //获取整个数据块
    i_header_buff_len = bytebuff_length(p_packet);
    if(p_comm_session->i_data_len > i_header_buff_len)
        return APM_L7_ANALYZE_TODO;

    p_header_buff = (char *)frmalloc(i_header_buff_len + 1);
    if(p_header_buff == NULL)
        goto ERROR;

    i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_header_buff_len);
    if(i_ret == FR_FAIL)
        goto ERROR;

    p_header_buff[i_header_buff_len] = '\0';

    if(p_comm_session->i_flag_multipart)
    {
        i_ret = multipart_data_parse(p_header_buff, i_header_buff_len, p_st_body_data, p_st_private, FR_YES);
        frfree(p_header_buff);
        return i_ret;
    }

    if(p_comm_session->i_flag_need == 0)
    {
        if(frxml_detect(p_header_buff,i_header_buff_len) == FR_FAIL)
        {
            //如果没有XML头 则尝试解析
            i_tmp_len = i_header_buff_len + strlen("<?xml version='1.0' encoding='UTF-8'?>\n");
            p_tmp = (char *)frmalloc(i_tmp_len + 1);
            if(p_tmp == NULL)
                return APM_L7_ANALYZE_FAIL;

            snprintf(p_tmp, i_tmp_len + 1, "<?xml version='1.0' encoding='UTF-8'?>\n%s", p_header_buff);

            if(frxml_parser_read(p_tmp, i_tmp_len) == FR_SUCC)
            {
                frfree(p_header_buff);
                p_header_buff = p_tmp;
                p_tmp = NULL;
                p_comm_session->i_flag_need = 1;
            }
            else
            {
                p_comm_session->i_flag_need = 2;
                frfree(p_tmp);
                p_tmp = NULL;
            }
        }
    }

    //soap 尝试解析
    i_ret = frsoap_parse_req(p_header_buff, i_header_buff_len, p_st_body_data);
    if(i_ret == FR_FAIL)
        goto ERROR;

    //url decode
    if(p_comm_session->i_url_encoded)
    {
        //url decode
        if(http_url_decode(p_header_buff, i_header_buff_len, &p_tmp) == FR_FAIL)
            goto ERROR;

        frfree(p_header_buff);
        p_header_buff = p_tmp;
        p_tmp = NULL;
    }

    if(strcasecmp(p_comm_session->arr_charset, "utf-8") != 0)
    {
        i_ret = iconv_to_utf8(p_header_buff, strlen(p_header_buff), p_comm_session->arr_charset, &p_tmp, (unsigned int *)&i_header_buff_len);
        if(i_ret != 0)
            goto ERROR;

        frfree(p_header_buff);
        p_header_buff = p_tmp;
        p_tmp = NULL;
    }

    //http.body
    snprintf(arr_head, sizeof(arr_head), "request.http.body.%d", 1);
    i_ret = frreport_body_l7_add_str(p_st_body_data, arr_head, p_header_buff);
    frfree(p_header_buff);

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

ERROR:
    if(p_header_buff)
        frfree(p_header_buff);

    if(p_tmp)
        frfree(p_tmp);

    return APM_L7_ANALYZE_FAIL;

}

/*\ resp 数据体分析 解析
 *
 * \p_packet                (Frbyte_Packet *        入力信息)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
FR_STATIC int __nghttp2_body_data_resp(Frbyte_Packet *p_packet, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    char *p_zdata = NULL;
    unsigned long ul_zdata_len = 0;
    int i_ret = 0;
    char *p_header_buff = NULL;
    int i_header_buff_len = 0;
    char *p_header_buff_tmp = NULL;
    char arr_head[128];
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_packet == NULL || p_st_private == NULL || p_st_private->p_http2_sess == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    if(p_comm_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //获取所需要的数据
    if(p_comm_session->i_flag_need == 1 && i_flag_need)
    {
        i_header_buff_len = bytebuff_length(p_packet);
        //获取整个数据块
        p_header_buff = (char *)frmalloc(i_header_buff_len + 1);
        if(p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;
        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_header_buff_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        p_header_buff[i_header_buff_len] = '\0';

        //multipart
        if(p_comm_session->i_flag_multipart)
        {
            i_ret = multipart_data_parse(p_header_buff, i_header_buff_len, p_st_body_data, p_st_private, FR_NO);
            frfree(p_header_buff);
            return i_ret;
        }

        //gizp解压
        if(p_comm_session->i_flag_gzip)
        {
            i_ret = frgzip_decompress((Byte *)p_header_buff, i_header_buff_len, &p_zdata, &ul_zdata_len);
            frfree(p_header_buff);
            if(i_ret != FR_SUCC)
            {
                if(p_zdata)
                    frfree(p_zdata);

                return APM_L7_ANALYZE_FAIL;
            }

        }
        else if(p_comm_session->i_flag_deflate)
        {
            //不用解压
            p_header_buff_tmp = (char *)frmalloc(i_header_buff_len + 10);
            memcpy(p_header_buff_tmp,"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00",10);
            memcpy(p_header_buff_tmp + 10,p_header_buff,i_header_buff_len);
            i_header_buff_len += 10;
            frfree(p_header_buff);
            p_header_buff = p_header_buff_tmp;

            i_ret = frgzip_decompress((Byte *)p_header_buff, i_header_buff_len, &p_zdata, &ul_zdata_len);
            frfree(p_header_buff);
            if(i_ret != FR_SUCC)
            {
                if(p_zdata)
                    frfree(p_zdata);

                return APM_L7_ANALYZE_FAIL;
            }
        }
        else
        {
            //不用解压
            p_zdata = p_header_buff;
            ul_zdata_len = i_header_buff_len;
        }

        if(p_comm_session->i_flag_data_type == HTTP_XML_DATA)
        {
            //字段名
            snprintf(arr_head, sizeof(arr_head), "response.http.body.%d", 1);
            i_ret = frreport_body_l7_add_str(p_st_body_data, arr_head, p_zdata);
            if(i_ret == FR_FAIL)
            {
                frfree(p_zdata);
                return APM_L7_ANALYZE_FAIL;
            }
            p_comm_session->p_xml_data = frstrdup(p_zdata);
            if(p_comm_session->p_xml_data == NULL)
            {
                frfree(p_zdata);
                return APM_L7_ANALYZE_FAIL;
            }

#ifdef FRDBG_XML_DATA_OUTPUT
                FILE *fp_xml_data = NULL;
            struct timeval st_time;
            char arr_tmp[128];

            gettimeofday (&st_time, NULL);
            snprintf(arr_tmp, sizeof(arr_tmp), "%d%d.txt", st_time.tv_sec, st_time.tv_usec);
            fp_xml_data = fopen(arr_tmp,"w");
            if(fp_xml_data)
            {
                fprintf(fp_xml_data, "%s\n", p_zdata);
                fclose(fp_xml_data);
            }
#endif
            frfree(p_zdata);
        }
        else if(p_comm_session->i_flag_data_type == HTTP_JSON_DATA)
        {
            //字段名
            snprintf(arr_head, sizeof(arr_head), "response.http.body.%d", 1);
            i_ret = frreport_body_l7_add_str(p_comm_session->p_st_body_data_resp, arr_head, p_zdata);
            if(i_ret == FR_FAIL)
            {
                frfree(p_zdata);
                return APM_L7_ANALYZE_FAIL;
            }
            frfree(p_zdata);
        }
        else
            frfree(p_zdata);

        return APM_L7_ANALYZE_SUCC;
    }

    return APM_L7_ANALYZE_SUCC;

}

/*\ http/2 date frame 解析
 *
 * \p_packet                (Frbyte_Packet *        入力信息)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
int nghttp2_data_parse(Frbyte_Packet *p_packet, unsigned int ui_data_len, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    uint8_t  u8_end_stream = 0;
    uint8_t u8_padded = 0;
    uint8_t u8_flags = 0;
    char *p_data = NULL;
    int i_ret = 0;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;
    uint32_t u32_stream_id = 0;

    if(p_packet == NULL || p_st_private == NULL || p_st_private->p_http2_sess == NULL || ui_data_len == 0)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    if(p_comm_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_packet, &u8_flags);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u8_end_stream = (u8_flags & (uint8_t)(0x01));
    u8_padded = (u8_flags & (uint8_t)0x08);

    //padded
    if(u8_padded)
    {
        i_ret = bytebuff_get_char(p_packet, &u8_padded);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;
    }

    //0... .... .... .... .... .... .... .... = Reserved: 0x00000000
    //.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
    i_ret = bytebuff_get_int(p_packet, 4, &u32_stream_id, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    u32_stream_id = u32_stream_id & 0x7fffffff;
    p_st_private->p_http2_sess->u32_stream_id = u32_stream_id;

    if(p_st_private->i_frame_type != 1)
        p_st_private->u32_current_resp_id = u32_stream_id;
    if(u8_padded)
    {
        if(p_packet->ui_remaining < u8_padded)
            return APM_L7_ANALYZE_FAIL;
    }

    //如果不是需要的数据  直接返回
    if(p_comm_session->i_flag_need != 1)
    {
        if(u8_end_stream == 0)
            return APM_L7_ANALYZE_TODO;
        else
            return APM_L7_ANALYZE_SUCC;
    }

    if(u8_end_stream == 0)
    {
        //存储data数据
        p_data = (char *)frmalloc(ui_data_len);
        if(p_data == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_get_bytes(p_packet, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }

        if(p_comm_session->p_st_body_data == NULL)
            p_comm_session->p_st_body_data = bytebuff_creat();

        i_ret = bytebuff_add(p_comm_session->p_st_body_data, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }

        frfree(p_data);
        return APM_L7_ANALYZE_TODO;

    }

    //单个数据包结束
    if (p_comm_session->p_st_body_data == NULL)
    {
        //todo 数据判断
        p_data = (char *)frmalloc(ui_data_len);
        if(p_data == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_get_bytes(p_packet, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }

        p_comm_session->p_st_body_data = bytebuff_creat();

        i_ret = bytebuff_add(p_comm_session->p_st_body_data, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }

        frfree(p_data);
    }
    else
    {
        //存储data数据
        p_data = (char *)frmalloc(ui_data_len);
        if(p_data == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_get_bytes(p_packet, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }

        if(p_comm_session->p_st_body_data == NULL)
            p_comm_session->p_st_body_data = bytebuff_creat();

        i_ret = bytebuff_add(p_comm_session->p_st_body_data, p_data, ui_data_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_data);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_data);
    }

    if(p_st_private->i_frame_type == 1)
        i_ret = __nghttp2_body_data_req(p_comm_session->p_st_body_data, p_st_private, p_st_body_data, i_flag_need);
    else if(p_st_private->i_frame_type == 2)
        i_ret = __nghttp2_body_data_resp(p_comm_session->p_st_body_data, p_st_private, p_st_body_data, i_flag_need);
    else
        return APM_L7_ANALYZE_FAIL;

    return i_ret;

}


/*\ http/2 frame 解析
 *
 * \p_data                  (char *             入力信息)
 * \ui_data_len             (unsigned int        数据长度)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
int nghttp2_analysis(char *p_data, unsigned int ui_data_len, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    int i_ret = 0;
    uint32_t u32_len = 0;
    uint8_t u8_type = 0;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;
    int i_frame_type = 0;

    if(p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_private->p_http2_sess == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    if(p_comm_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(ui_data_len == 24 && memcmp(p_data, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0)
    {
        if(i_flag_need)
        {
            i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, "PRI * HTTP/2.0");
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

            p_http2_session->u32_stream_id = 0x80000000;
            p_st_private->i_flag_report = 1;
        }

        return APM_L7_ANALYZE_SUCC;
    }

    if(p_comm_session->p_st_data == NULL)
        p_comm_session->p_st_data = bytebuff_creat();

    if(p_http2_session->u8_type == HTTP2_DATA && p_comm_session->i_flag_need != 1)
    {
        p_st_private->i_flag_report = 1;

        if(p_comm_session->i_data_len == (int)ui_data_len)
        {
            p_comm_session->i_data_len = 0;
            return APM_L7_ANALYZE_SUCC;
        }
        else if(p_comm_session->i_data_len > (int)ui_data_len)
        {
            p_comm_session->i_data_len -= ui_data_len;
            return APM_L7_ANALYZE_TODO;
        }
        else
        {
            ui_data_len -= p_comm_session->i_data_len;
            p_data += p_comm_session->i_data_len;
            p_comm_session->i_data_len = 0;

            bytebuff_skip(p_comm_session->p_st_data, p_comm_session->p_st_data->ui_remaining);
            bytebuff_truncate(p_comm_session->p_st_data);
        }
    }

    i_ret = bytebuff_add(p_comm_session->p_st_data, p_data, ui_data_len);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

ANALYSIS:

    i_ret = bytebuff_get_int(p_comm_session->p_st_data, 3, &u32_len, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_comm_session->p_st_data, &u8_type);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(u8_type == HTTP2_CONTINUATION)
        u8_type = p_http2_session->u8_type;
    else
        p_http2_session->u8_type = u8_type;

    switch (p_http2_session->u8_type)
    {
        case HTTP2_DATA:
            if(p_comm_session->i_flag_need != 1)
            {
                p_st_private->i_flag_report = 1;
                if(p_comm_session->i_data_len == 0)
                    p_comm_session->i_data_len = u32_len;

                if(p_comm_session->i_data_len == (int)p_comm_session->p_st_data->ui_remaining - 5)
                {
                    p_comm_session->i_data_len = 0;
                    return APM_L7_ANALYZE_SUCC;
                }
                else if(p_comm_session->i_data_len > (int)p_comm_session->p_st_data->ui_remaining - 5)
                {
                    p_comm_session->i_data_len -= p_comm_session->p_st_data->ui_remaining - 5;
                    return APM_L7_ANALYZE_TODO;
                }
                else
                {
                    ui_data_len -= p_comm_session->i_data_len;
                    p_data += p_comm_session->i_data_len;
                    p_comm_session->i_data_len = 0;

                    bytebuff_skip(p_comm_session->p_st_data, p_comm_session->p_st_data->ui_remaining);
                    bytebuff_truncate(p_comm_session->p_st_data);

                    i_ret = bytebuff_add(p_comm_session->p_st_data, p_data, ui_data_len);
                    if(i_ret == FR_FAIL)
                        return APM_L7_ANALYZE_FAIL;

                    p_http2_session->u8_type = 0xff;
                    goto ANALYSIS;
                }
            }

            p_st_private->i_flag_report = 1;
            if(p_comm_session->i_data_len == 0)
                p_comm_session->i_data_len = u32_len;


            if(p_comm_session->i_data_len >(int) p_comm_session->p_st_data->ui_remaining - 5)
            {
                bytebuff_rewind(p_comm_session->p_st_data);
                return APM_L7_ANALYZE_TODO;
            }

            i_ret = nghttp2_data_parse(p_comm_session->p_st_data, u32_len, p_st_private, p_st_body_data, i_flag_need);
            break;

        case HTTP2_HEADERS:
            if(u32_len > p_comm_session->p_st_data->ui_remaining - 5)
            {
                bytebuff_rewind(p_comm_session->p_st_data);
                return APM_L7_ANALYZE_TODO;
            }
            p_st_private->i_flag_report = 1;
            i_ret = nghttp2_header_parse(p_comm_session->p_st_data, u32_len, p_st_private, p_st_body_data, i_flag_need);
            break;

        case HTTP2_PUSH_PROMISE:
            if(u32_len > p_comm_session->p_st_data->ui_remaining - 5)
            {
                bytebuff_rewind(p_comm_session->p_st_data);
                return APM_L7_ANALYZE_TODO;
            }
            i_frame_type = p_st_private->i_frame_type;
            p_st_private->i_frame_type = 3;
            p_st_private->i_flag_report = 1;
            i_ret = nghttp2_push_promise_parse(p_comm_session->p_st_data, u32_len - 4, p_st_private, p_st_body_data, i_flag_need);
            p_st_private->i_frame_type = i_frame_type;
            break;

        case HTTP2_SETTINGS:
        case HTTP2_PING:
            p_st_private->i_flag_report = 0;
            if(u32_len > p_comm_session->p_st_data->ui_remaining - 5)
            {
                bytebuff_rewind(p_comm_session->p_st_data);
                return APM_L7_ANALYZE_TODO;
            }

            if(bytebuff_skip(p_comm_session->p_st_data, u32_len + 5) == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

            i_ret = APM_L7_ANALYZE_SUCC;

            break;

        case HTTP2_PRIORITY:
        case HTTP2_RST_STREAM:
        case HTTP2_GOAWAY:
        case HTTP2_WINDOW_UPDATE:
        case HTTP2_ALTSVC:
        case HTTP2_BLOCKED:
            p_st_private->i_flag_report = 0;

            if(u32_len > p_comm_session->p_st_data->ui_remaining - 5)
            {
                bytebuff_rewind(p_comm_session->p_st_data);
                return APM_L7_ANALYZE_TODO;
            }

            if(bytebuff_skip(p_comm_session->p_st_data, u32_len + 5) == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

            i_ret = APM_L7_ANALYZE_SUCC;

            break;

        case HTTP2_CONTINUATION:
        default:
            return APM_L7_ANALYZE_FAIL;
    }

    if(i_ret != APM_L7_ANALYZE_FAIL && p_comm_session->p_st_data->ui_remaining)
    {
        if(p_st_private->i_flag_report)
            p_http2_session->i_unreported = 1;
        goto ANALYSIS;
    }

    if(p_http2_session->i_unreported == 1)
    {
        p_http2_session->i_unreported = 0;
        p_st_private->i_flag_report = 1;
    }
    return i_ret;

}


/*\ http/2 header detect
 *
 * \p_data                  (char *             入力信息)
 * \ui_data_len             (unsigned int        数据长度)
 * \p_st_private            (L7session_http_private *       私有信息)
 * \p_st_body_data          (Frreport_body_data *       上报链表)
 * \i_flag_need             (是否上报)
 *
 * \return                  成功：APM_L7_ANALYZE_SUCC\n
 *                          失败：APM_L7_ANALYZE_FAIL\n
 */
int __http2_header_detect(char *p_data, unsigned int ui_data_len, L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
    int i_ret = 0;
    uint32_t u32_len = 0;
    uint8_t u8_type = 0;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_private->p_http2_sess == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(i_flag_need && p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    if(p_comm_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(ui_data_len == 24 && memcmp(p_data, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0)
    {
        if(i_flag_need)
        {
            i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, "PRI * HTTP/2.0");
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

            p_st_private->i_flag_report = 1;
        }

        return APM_L7_ANALYZE_SUCC;
    }

    if(p_comm_session->p_st_data == NULL)
        p_comm_session->p_st_data = bytebuff_creat();

    i_ret = bytebuff_add(p_comm_session->p_st_data, p_data, ui_data_len);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_int(p_comm_session->p_st_data, 3, &u32_len, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_comm_session->p_st_data, &u8_type);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    switch (u8_type)
    {
        case HTTP2_HEADERS:
            p_st_private->i_flag_report = 1;
            i_ret = nghttp2_header_parse(p_comm_session->p_st_data,u32_len, p_st_private, p_st_body_data, i_flag_need);
            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

    return i_ret;

}


int nghttp2_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_data = NULL;
    unsigned int ui_date_len = 0, ui_temp = 0;
    L7session_http_private *p_st_private = NULL;
    int i_ret = 0, i_ret_fun = 0;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_st_packet == NULL || p_st_conn==NULL)
        return APM_L7_IS_NO;

    p_data = p_st_packet->p_payload;
    ui_date_len = p_st_packet->ui_payload_len;

    if(ui_date_len == 24)
    {
        //Magic: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
        if(memcmp(p_data, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0)
        {
            //todo
            i_ret_fun = frct_get_direct_known(p_st_conn);
            if( i_ret_fun == FR_DIRECT_UNKNOWN)
                frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);

//            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip
//                    , p_st_packet->dst_port, NULL, 0);

            return APM_L7_IS_YES;
        }
    }
    else
    {
        if(ui_date_len < 9)
            return APM_L7_IS_NO;

        ui_temp = ui_temp & p_data[0] << 2;
        ui_temp = ui_temp & p_data[1] << 1;
        ui_temp = ui_temp & p_data[2] << 0;

        if(ui_temp != ui_date_len - 9)
            return APM_L7_IS_NO;
    }

    p_st_private = http_private_create();
    if(p_st_private == NULL)
        return APM_L7_IS_NO;

    p_st_private->p_http2_sess = http2_session_create();
    if(p_st_private->p_http2_sess == NULL)
        return APM_L7_IS_NO;

    p_http2_session = p_st_private->p_http2_sess;
    p_comm_session = p_http2_session->p_st_comm_session;

    i_ret = __http2_header_detect(p_data, ui_date_len, p_st_private, NULL, FR_NO);
    if(i_ret == APM_L7_ANALYZE_SUCC)
    {
        i_ret_fun = frct_get_direct_known(p_st_conn);
        if( i_ret_fun == FR_DIRECT_UNKNOWN)
        {
            if(p_comm_session->l_response_code)
            {
                frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);

//                frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip
//                        , p_st_packet->dst_port, NULL, 0);
            }
            else if(p_comm_session->p_uri)
            {
                frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);

//                frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip
//                        , p_st_packet->dst_port, NULL, 0);

            }
            else
            {
                //todo
                http_session_destroy(p_st_private);
                return APM_L7_IS_NO;
            }

        }

        http_session_destroy(p_st_private);
        return APM_L7_IS_YES;
    }

    http_session_destroy(p_st_private);
    return APM_L7_IS_NO;
}


